﻿/**
 * Created by Administrator on 2017/2/17 0017.
 */
//定义一定时器,用来接受设置的定时器
var timer;
//这几个函数是在公开函数的方法,为静态成员
//选择器方法,返回的是document.querySelectorAll返回值
$.select = function (selector) {
    return document.querySelectorAll(selector);
}
//判断传入的对象是不是数组或者伪数组,即能不能用for循环遍历
$.isArrayLike = function (obj) {
    //obj借用toString方法,返回的是[object obj类型]
    if (toString.call(obj).slice(8, -1) === "Array") {
        return true;
    }
    //如果传入的是字符串或者函数直接返回false
    if (typeof obj == 'string' || typeof obj == 'function') {
        return false;
    }
    //如果obj有length属性返回属性值,没有的话length为false
    var length = 'length' in obj && obj.length;
    return typeof length === "number" && length >= 0;
}
$.each = function (obj, callback) {
    //如果isArrayLike为TRUE,for循环遍历
    if ($.isArrayLike(obj)) {
        for (var i = 0; i < obj.length; i++) {
            /*call后面的第一个参数改变this指向,实现each遍历时this可以代表当前遍历对象
             如果返回值是false的话,就跳出循环
             */
            if (callback.call(obj[i], i, obj[i]) === false) break;
        }
    } else {
        for (var k in obj) {
            /*call后面的第一个参数改变this指向,实现each遍历时this可以代表当前遍历对象
             如果返回值是false的话,就跳出循环
             */
            if (callback.call(obj[k], k, obj[k]) === false) break;
        }
    }
    //实现链式编程
    return this;
}
$.map = function (obj, callback) {
    //map方法遍历返回的是一个数组,创建一个新数组用来接收数据
    var arr = [], tmp;
    //如果isArrayLike为TRUE,for循环遍历
    if ($.isArrayLike(obj)) {
        for (var i = 0; i < obj.length; i++) {
            tmp = callback(obj[i], i);
            //如果回调函数的返回值不为null,数组就接受这个数据,包括undefined
            if (tmp !== null) {
                arr.push(tmp)
            }
        }
    } else {
        for (var k = 0; k < obj.length; k++) {
            tmp = callback(obj[k], k);
        }
        //如果回调函数的返回值不为null,数组就接受这个数据,包括undefined
        if (tmp !== null) {
            arr.push(tmp)
        }
    }
    //返回这个数组,进行扁平化处理,如果arr里面push的是数组也能解析
    return arr.concat.apply([], arr);
}
//如果传入的是html字符串,创建一个div用来接收传入的字符串
$.parseHTML = function (str) {
    var div = document.createElement("div");
    div.innerHTML = str;
    //返回这个div的子节点,可以得到传入html字符串对应的标签
    //return div.childNodes;

    return $.map(div.childNodes, function (v, i) {
        return v;
    })
}

// 去重算法
$.contains = function (arr, item) {
    // return arr.indexOf( item ) > -1;
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == item) {
            return true;
        }
    }
    return false;
}
$.unique = function (arr) {
    var newArr = [];
    for (var i = 0; i < arr.length; i++) {
        if (!$.contains(newArr, arr[i])) {
            newArr.push(arr[i]);
        }
    }
    return newArr;
}
$.pushStack = function (array) {
    // this 以前的 Itcast 对象
    // 栈结构
    var tmp = this.constructor();
    push.apply(tmp, array);
    tmp.prevObject = this;
    return tmp;
}

function $(selector) {
    return new $.prototype.init(selector);
}
$.prototype = {
    constructor: $,
    length: 0,
    //init是构造函数,每次创建出来一个实例对象即为选择器返回的值
    init: function (selector) {
        // 传入的如果是 0, '', nulll, undefined
        if (!selector) return this;
        //判断传入的是不是字符串
        if (typeof selector == "string") {
            //判断传入的是不是html字符串,如果是html字符串,则向构造函数的实例中添加parseHTML方法的返回值
            if (/^\s*</.test(selector)) {
                [].push.apply(this, $.parseHTML(selector))
            } else {
                //如果传入的是选择器,则向构造函数的实例中添加select方法的返回值
                [].push.apply(this, $.select(selector));
            }
        }
        //如果传入的是dom对象,dom对象有nodetype属性
        if (selector.nodeType) {
            //把这个dom对象加到新创建的$对象中
            [].push.call(this, selector);
        }
        //如果传入的是$对象,其constructor(构造函数)为$
        if (selector.constructor == $) {
            //如果传入的$对象,新创建一个$对象,分别把传入的对象的每一项加到新创建的对象中
            [].push.apply(this, selector);
        }
        //如果传入的是函数
        if (typeof selector == 'function') {
            window.addEventListener('load', selector)
        }
    }
}
//对外公开的函数和构造函数共享一个原型,这样在给对外公开函数原型添加方法的时候,构造函数也可以访问这个方法,实现添加即可用
$.prototype.init.prototype = $.prototype;
//给静态成员和原型是同时添加扩展方法的方法
$.extend = $.prototype.extend = function (obj) {
    for (var k in obj) {
        this[k] = obj[k];
    }
    //实现链式编程
    return this;
}
//给原型添加方法,即添加实例成员
$.prototype.extend({
    each: function (callback) {
        return $.each(this, callback);
    },
    map: function (callback) {
        return $.map(this, callback);
    },
    //转换成数组的方法
    toArray: function () {
        //slice是截取数组,如果不传参数则是从第一项到最后一项返回一个新的数组
        return [].slice.call(this);
        //或是利用map方法返回一个新数组的特性进行遍历
        /*    return  $.map(this, function (v, i) {
         return v;
         })
         */
    },
    //利用get方法获取的是标准dom元素
    get: function (n) {
        //如果不传参数,那么就执行toArray方法
        if (n === undefined) {
            return this.toArray()
        }
        ;
        //如果传入的参数小于0,则时从后面获取,length+n恰是要获取的元素
        if (n < 0) {
            return this[this.length + n];
        } else {
            return this[n];
        }
    },
    //eq方法同get方法类似,不过获取的不是dom元素
    eq: function (n) {
        //如果不传参数,那么就执行toArray方法
        if (n == undefined) {
            return this.constructor();
        }
        ;
        //利用构造函数不传参数获取一个空的对象
        var obj = this.constructor();
        //obj借用数组的push方法,将第n项添加到空对象当中
        if (this.get(n)) {
            [].push.call(obj, this.get(n));
        }

        //返回这个对象
        return obj;
    },
    first: function () {
        //利用构造函数不传参数获取一个空的对象
        var obj = this.constructor();
        //obj借用数组的push方法,将第0项添加到空对象当中
        [].push.call(obj, this.get(0));
        //返回这个对象
        return obj;

        //或是直接用eq方法
        // return this.eq(0);
    },
    last: function () {
        //利用构造函数不传参数获取一个空的对象
        var obj = this.constructor();
        //obj借用数组的push方法,将最末项添加到空对象当中
        [].push.call(obj, this.get(-1));
        //返回这个对象
        return obj;
        //或是直接用eq方法
        //return this.eq(-1);
    },
    //设置样式方法
    css: function (key, value) {
        ////采用each方法遍历当前对象,给每个对象都添加样式
        //$.each(this, function (i, v) {
        //    //对传入的对象遍历,把每个属性都添加上
        //    for (var k in obj) {
        //        v.style[k] = obj[k];
        //    }
        //})
        ////返回this,实现链式编程
        //return this;
        if (Object.prototype.slice.call(key).slice(8, -1) == "Object") {
            return this.each(function () {
                for (var k in key) {
                    this[k] = key[k];
                }
            })
        } else if (typeof key == 'string') {
            if (value === undefined) {
                return this[0].style[key] || window.getComputedStyle(this[0])[key];
            } else if (typeof value == 'function') {
                // 条件设置
                // 给每一个 DOM 元素设置该样式, 但是样式值由函数返回值决定
                return this.each(function (i) {
                    this.style[key] = value(i, this.style[key] || window.getComputedStyle(this)[key])
                });
            }
        } else if ($.isArrayLike(key)) {
            var obj = {}, target = this[0];
            $.each(key, function (i, v) {
                obj[v] = target[v] || window.getComputedStyle(target)[v];
            });
            return obj
        }

    },
    //类似jq的颜色渐变的动画,逐渐出现
    fadeIn: function () {
        //定义一个初始值
        var opacity = 0;
        //定义一个变量接收this
        var thi = this;
        if (timer) {
            // alert(1);
            clearInterval(timer);
        }
        //设置定时器,用来逐渐改变透明度
        timer = setInterval(function () {
            //每次增加opacity值,增加透明度
            opacity++;
            //用each方法遍历this,给每一项都设置
            $.each(thi, function (i, v) {
                v.style.opacity = opacity / 100;

            });
            //当透明度达到1时,清除定时器
            if (opacity == 100) {
                clearInterval(timer);
            }
        }, 20)
        //实现链式编程
        return this;
    },
    fadeOut: function () {
        //clearInterval(thi.timer);
        //定义一个初始值
        if (timer) {
            clearInterval(timer);
        }
        var opacity = 100;
        //定义一个变量接收this
        var thi = this;
        //设置定时器
        timer = setInterval(function () {
            opacity--;
            //用each方法遍历this,给每一项都设置
            $.each(thi, function (i, v) {
                v.style.opacity = opacity / 100;
            })
            //当透明度降到0时,清除定时器
            if (opacity == 0) {
                clearInterval(timer);
            }
        }, 20)
    },
    //添加逐渐消失动画的方法
    hide: function (time, callback) {
        //当没有传时间函数的时候,给time一个默认的值
        if (!time || typeof time != "number") {
            time = 600;
        }
        //定义变量接收this
        var thi = this;
        // var i=0;
        //宽高渐变,设置变量每次的新的宽高给元素设置
        var newWidth, newHeight;
        //添加定时器
        timer = setInterval(function () {
            //  i++;
            //遍历this,给每一个都设置
            $.each(thi, function (i, v) {
                //获取初始宽高
                var width = this.offsetWidth;
                var height = this.offsetHeight;
                //给新的宽高赋值,每次改变的量为width*(20/time),当最后值不足再减一次的时候,直接赋值为0
                newWidth = width - width * (20 / time) < width * (20 / time) ? 0 : parseInt(width - width * (20 / time));
                newHeight = height - height * (20 / time) < height * (20 / time) ? 0 : parseInt(height - height * (20 / time));
                this.style.width = newWidth + "px";
                this.style.height = newHeight + "px";
            })
            //当元素的宽高都是0的时候,清除定时器,然后调用回调函数
            if (newWidth == 0 && newHeight == 0) {
                //清除定时器
                clearInterval(timer);
                //当没有传入回调函数的时候不调用,传入回调函数就调用
                callback && callback();
            }
        }, 20);
        //实现链式编程
        return this;
    },
    //next: function () {
    //    //定义一个空对象用来接收当前对象的每一项的下一项
    //    var tmp = [];
    //    //创建一个空的$对象
    //    var obj = this.constructor();
    //    //对当前对象遍历,得到每一项的下一个
    //    this.each(function (i, v) {
    //        //把每一项的相邻元素添加到数组中
    //        tmp.push(v.nextElementSibling);
    //    });
    //    //$对象obj借用push方法把数组tmp追加到自身
    //    [].push.apply(obj, tmp);
    //    //返回这个$对象obj
    //    return obj;
    //},
    //prev: function () {
    //    //定义一个空对象用来接收当前对象的每一项的上一项
    //    var tmp = [];
    //    //创建一个空的$对象
    //    var obj = this.constructor();
    //    //对当前对象遍历,得到每一项的下一个
    //    this.each(function (i, v) {
    //        //把每一项的相邻上一个元素添加到数组中
    //        tmp.push(v.previousElementSibling);
    //    });
    //    //$对象obj借用push方法把数组tmp追加到自身
    //    [].push.apply(obj, tmp);
    //    //返回这个$对象obj
    //    return obj;
    //},
    //parent: function (selector) {
    //    //用一个数组接收this的所有父元素
    //    var tmp = $.unique($.map(this, function (v, i) {
    //        return v.parentNode;
    //    }));
    //    var obj = this.constructor();
    //    //如果函数传的有参数即过滤器
    //    if (selector) {
    //        //创建一个secletor的$对象
    //        var select = this.constructor(selector);
    //        //创建一个空数组接收父元素和过滤器的交集
    //        var tem = [];
    //        for (var i = 0; i < select.length; i++) {
    //            for (var j = 0; j < tmp.length; j++) {
    //                if (select[i] === tmp[j]) {
    //                    tem.push(tmp[j]);
    //                }
    //            }
    //        }
    //        //把交集数组加到$对象中
    //        [].push.apply(obj, tem);
    //        return obj;
    //    } else {
    //        //没有过滤器的话,就把所有父元素的数组加到$对象中
    //        obj = this.constructor();
    //        [].push.apply(obj, tmp);
    //        return obj;
    //    }
    //},
    //nextAll: function (selector) {
    //    var tmp = [];
    //    this.each(function (i, v) {
    //        var v = v.nextElementSibling;
    //        tmp.push(v);
    //        while (v.nextElementSibling && v.nextElementSibling.nodeName != "SCRIPT") {
    //            v = v.nextElementSibling;
    //            tmp.push(v);
    //        }
    //    })
    //    tmp = $.unique(tmp);
    //    var obj = this.constructor();
    //    //如果函数传的有参数即过滤器
    //    if (selector) {
    //        //创建一个secletor的$对象
    //        var select = this.constructor(selector);
    //        //创建一个空数组接收父元素和过滤器的交集
    //        var tem = [];
    //        for (var i = 0; i < select.length; i++) {
    //            for (var j = 0; j < tmp.length; j++) {
    //                if (select[i] === tmp[j]) {
    //                    tem.push(tmp[j]);
    //                }
    //            }
    //        }
    //        //把交集数组加到$对象中
    //        [].push.apply(obj, tem);
    //        return obj;
    //    } else {
    //        //没有过滤器的话,就把所有父元素的数组加到$对象中
    //        obj = this.constructor();
    //        [].push.apply(obj, tmp);
    //        return obj;
    //    }
    //},
    //prevAll: function (selector) {
    //    var tmp = [];
    //    this.each(function (i, v) {
    //        var v = v.previousElementSibling;
    //        tmp.push(v);
    //        while (v.previousElementSibling && v.previousElementSibling.nodeName != "SCRIPT") {
    //            v = v.previousElementSibling;
    //            tmp.unshift(v);
    //        }
    //    })
    //    tmp = $.unique(tmp);
    //    var obj = this.constructor();
    //    //如果函数传的有参数即过滤器
    //    if (selector) {
    //        //创建一个secletor的$对象
    //        var select = this.constructor(selector);
    //        //创建一个空数组接收父元素和过滤器的交集
    //        var tem = [];
    //        for (var i = 0; i < select.length; i++) {
    //            for (var j = 0; j < tmp.length; j++) {
    //                if (select[i] === tmp[j]) {
    //                    tem.push(tmp[j]);
    //                }
    //            }
    //        }
    //        //把交集数组加到$对象中
    //        [].push.apply(obj, tem);
    //        return obj;
    //    } else {
    //        //没有过滤器的话,就把所有父元素的数组加到$对象中
    //        obj = this.constructor();
    //        [].push.apply(obj, tmp);
    //        return obj;
    //    }
    //},
    //siblings: function (selector) {
    //    var beforeArr = this.prevAll().toArray()
    //    var afterArr = this.nextAll().toArray();
    //    var tmp = beforeArr.concat(afterArr);
    //    console.log(tmp);
    //    var obj = this.constructor();
    //    //如果函数传的有参数即过滤器
    //    if (selector) {
    //        //创建一个secletor的$对象
    //        var select = this.constructor(selector);
    //        //创建一个空数组接收父元素和过滤器的交集
    //        var tem = [];
    //        for (var i = 0; i < select.length; i++) {
    //            for (var j = 0; j < tmp.length; j++) {
    //                if (select[i] === tmp[j]) {
    //                    tem.push(tmp[j]);
    //                }
    //            }
    //        }
    //        //把交集数组加到$对象中
    //        [].push.apply(obj, tem);
    //        return obj;
    //    } else {
    //        //没有过滤器的话,就把所有父元素的数组加到$对象中
    //        obj = this.constructor();
    //        [].push.apply(obj, tmp);
    //        return obj;
    //    }
    //},
    siblings: function () {
        var arr1 = this.prevAll().toArray();
        var arr2 = this.nextAll().toArray();

        return this.pushStack(arr1.concat(arr2));
    },
    pushStack: function (array) {
        // this 以前的 Itcast 对象
        // 栈结构
        var tmp = this.constructor();
        [].push.apply(tmp, array);
        tmp.prevObject = this;
        return tmp;
    },
    end: function () {
        return this.prevObject || this.constructor();
    },
    text: function (text) {
        if (text === undefined) {
            var str = "";
            this.each(function () {
                if (typeof this.innerText == 'string') {
                    str += this.innerText;
                } else {
                    str += this.textContent;
                }
            })
            return str;
        } else if (typeof text == "string") {
            return this.each(function () {
                if (typeof this.innerText == 'string') {
                    this.innerText = text;
                } else {
                    this.textContent = text
                }
            })
        }
    },
    html: function (html) {
        if (html === undefined) {
            return this[0].innerHTML;
        } else if (typeof html == "string") {
            return this.each(function () {
                this.innerHTML = html;
            })
        }
    },
    val: function () {

    },
    attr: function (attrName, attrValue) {
        var mark = 'checked, selected, readonly, disabled'.split(',');
        if (typeof attrName == 'string') {
            if (attrValue == undefined) {
                if (mark.indexOf(attrValue) != -1) {
                    return this[0][attrName]
                } else {
                    return this[0].getAttribute(attrName)
                }
            } else if (typeof attrValue === 'function') {
        // 取值有回调函数决定
        // 回调函数含有一个 index 属性, 用于描述是哪一个 元素使用该对象函数( 简化后不考虑第二个参数 )
                return this.each(function (i) {
                    if (mark.indexOf(attrName) != -1) {
                        this[attrName] = attrValue(i);
                    } else {
                        this.setAttribute(attrName, attrValue(i));
                    }
                });
            }else{
                // 设置单个值
                // 也是设置 每一个 DOM 元素
                return this.each( function () {
                    if ( mark.indexOf( attrName ) != -1 ) {
                        this[ attrName ] = attrValue;
                    } else {
                        this.setAttribute( attrName, attrValue );
                    }
                });
            }
        }else if ( Object.prototype.toString.call( attrName ) === '[object Object]' ) {
            // 对象, 设置多个属性
            // 给 this 中的 每一个 DOM 元素都设置 attrName 中的每一个属性
            return this.each(function () {
                var that = this;
                Itcast.each( attrName, function ( k, v ) {
                    if ( mark.indexOf( k ) != -1 ) {
                        that[ k ] = v;
                    } else {
                        that.setAttribute( k, v );
                    }
                });
            });

        }

    },
    prop: function (attrName,attrValue) {
        if ( typeof attrName == 'string' ) {
            if ( attrValue === undefined ) {
                return this[ 0 ][ attrName ];

            } else if ( typeof attrValue  === 'function' ) {
                return this.each( function ( i ) {
                    this[ attrName ] = attrValue( i );
                });

            } else {
                return this.each( function () {
                    this[ attrName ] = attrValue;
                });
            }

        } else if ( Object.prototype.toString.call( attrName ) === '[object Object]' ) {
            return this.each(function () {
                var that = this;
                Itcast.each( attrName, function ( k, v ) {
                    that[ k ] = v;
                });
            });

        }
    },
    val: function () {
        return this[0].value;
    }
})
















